#include <crow/http_response.h>

#include "common/api/client.h"

#include "common/log/crow_logger.hpp"
#include "common/log/user_log.hpp"

#include "common/more/uuid.h"

#include "common/helpers/container_helper.hpp"
#include "common/helpers/crow_helper.h"

#include "common/helpers/context_helper.h"

#include "translations.h"
#include "ui_controller.h"

#include "ui_root_handler.h"

namespace
{

crow::mustache::context menuContext(const UiSessionPtr session)
{
    auto tr = session->translation();
    auto trMainMenu = tr["mainMenu"];
    auto trBreadCrumbs = tr["breadCrumbs"];
    auto trRootPage = tr["pages"]["root"];
    auto trRootTabs = trRootPage["tabs"];

    Common::ContextList mainMenu;
    mainMenu << Common::ContextValue(
        { { "link", "/users/" },
          { "caption", trMainMenu["users"] },
          { "icon", "ri-user-fill" } }
    );
    mainMenu << Common::ContextValue(
        { { "link", "/roles/" },
          { "caption", trMainMenu["roles"] },
          { "icon", "ri-shield-user-fill" } }
    );
    mainMenu << Common::ContextValue(
        { { "link", "/teams/" },
          { "caption", trMainMenu["teams"] },
          { "icon", "ri-team-fill" } }
    );
    mainMenu << Common::ContextValue(
        { { "link", "/workflows/" },
          { "caption", trMainMenu["workflows"] },
          { "icon", "ri-mind-map" } }
    );
    mainMenu << Common::ContextValue(
        { { "link", "/item_types/" },
          { "caption", trMainMenu["itemTypes"] },
          { "icon", "ri-article-fill" } }
    );

    Common::ContextList breadCrumbs;
    breadCrumbs << Common::ContextValue(
        { { "link", "" },
          { "caption", trBreadCrumbs["main"] },
          { "isLast", true } }
    );

    Common::ContextList tabs;
    tabs << Common::ContextValue(
        { { "link", "/" },
          { "caption", trRootTabs["common"] },
          { "isActive", true } }
    );
    tabs << Common::ContextValue(
        { { "link", "/items" },
          { "caption", trRootTabs["items"] } }
    );
    tabs << Common::ContextValue(
        { { "link", "/projects" },
          { "caption", trRootTabs["projects"] } }
    );
    tabs << Common::ContextValue(
        { { "link", "/reports" },
          { "caption", trRootTabs["reports"] } }
    );

    return crow::mustache::context({
        { "tr", trRootPage },
        { "mainMenu", mainMenu.data() },
        { "breadCrumbs", breadCrumbs.data() },
        { "tabs", tabs.data() },
        { "sessionMessages", session->sessionMessages().toContextList().data() },
    });
}

crow::response rootResponse(Ui::UiController* controller, const UiSessionPtr session)
{
    auto context = menuContext(session);
    return crow::response(controller->rootPageTemplate().render(context));
}

crow::response loginResponse(
    Ui::UiController* controller,
    crow::mustache::context context = crow::mustache::context()
)
{
    context["tr"] = Ui::defaultTranslation;
    crow::response response(controller->loginPageTemplate().render(context));
    Common::setSessionUuid(response, Uuids::nilUuid());
    return response;
}

} // namespace

namespace Ui
{

void RootHandler::setup(crow::App<>& crowApplication, UiController* controller)
{
    CROW_ROUTE(crowApplication, "/")
        .methods("GET"_method)(
            [controller](const crow::request& request)
            {
                const Uuids::Uuid sessionUuid = Common::currentSessionUuid(request);
                const auto session = controller->session(sessionUuid);
                if (!session)
                    return loginResponse(controller);

                return rootResponse(controller, session);
            }
        );

    CROW_ROUTE(crowApplication, "/")
        .methods("POST"_method)(
            [controller](const crow::request& request)
            {
                const crow::query_string params("?" + request.body);
                const auto keys = params.keys();
                if (Common::contains(keys, "user")
                    && Common::contains(keys, "password"))
                {
                    const auto user = params.get("user");
                    const auto password = params.get("password");
                    const auto loginResult = controller->datenaroGate()->login(user, password);
                    if (loginResult.m_isSuccess)
                    {
                        auto session = controller->addSession(
                            loginResult.m_sessionUuid,
                            loginResult.m_id
                        );
                        crow::response response = rootResponse(controller, session);
                        Common::setSessionUuid(response, loginResult.m_sessionUuid);
                        SESSION_LOG_INFO
                            << "Выполнен вход пользователя, идентификатор сессии: "
                            << Uuids::uuidToString(loginResult.m_sessionUuid);
                        return response;
                    }

                    LOG_WARN
                        << user << " | "
                        << "Неудачный вход пользователя: " << loginResult.m_reason;

                    auto trActions = Ui::defaultTranslation["actions"];
                    crow::mustache::context context {
                        {
                            "sessionMessages",
                            UiSessionMessage(
                                /* Заголовок */
                                trActions["login"],
                                /* Текст */
                                trActions["noAccess"],
                                /* Тип сообщения */
                                UiSessionMessage::Alert
                            ).toContextValue()
                        },
                    };
                    crow::response response = loginResponse(controller, context);
                    Common::setSessionUuid(response, Uuids::nilUuid());
                    return response;
                }

                const Uuids::Uuid sessionUuid = Common::currentSessionUuid(request);
                const auto session = controller->session(sessionUuid);
                if (!session)
                    return loginResponse(controller);

                return rootResponse(controller, session);
            }
        );

    CROW_ROUTE(crowApplication, "/error404")
        .methods("GET"_method)(
            [controller](const crow::request& request)
            {
                const Uuids::Uuid sessionUuid = Common::currentSessionUuid(request);
                const auto session = controller->session(sessionUuid);
                if (!session)
                    return loginResponse(controller);

                // TODO: добавить переводы.
                crow::mustache::context context;
                return crow::response(controller->error404().render(context));
            }
        );
}

} // namespace Ui
